/******************************************************************************
 * Filename : uc_string.c
 * Copyright:
 * Created  : 2011-1-6 by franco.yin
 * Description -
 *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

#include "uc_string.h"

static const UC_U8 ucstr_charmap[] = {
	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};

static const UC_U8 ucstr_flag_key[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };

int
ucstr_byte_to_str(char* pSrc, int nSrcLen, char *pDst)
{
	int i = 0;
	int n = 0;

	for(i = 0;i < nSrcLen; i++) {
		n += sprintf(pDst + n, "%02x", (unsigned char)(*(pSrc + i)));
	}

	return n;
}

int
ucstr_str_to_byte(char* pSrc, int nSrcLen, char* pDst)
{
	int i = 0;
	int nSrcLength = nSrcLen / 2;

	if((nSrcLen % 2) != 0) {
		return ERROR;
	}

	for (i = 0; i < nSrcLength; i++) {
		if (*pSrc >= '0' && *pSrc <= '9') {
			*pDst = (*pSrc - '0') << 4;
		} else if(*pSrc >= 'A' && *pSrc <= 'F'){
			*pDst = (*pSrc - 'A' + 10) << 4;
		} else if(*pSrc >= 'a' && *pSrc <= 'f') {
			*pDst = (*pSrc - 'a' + 10) << 4;
		} else {
			*pDst = 0;
		}
		pSrc++;

		if (*pSrc >= '0' && *pSrc <= '9') {
			*pDst |= *pSrc - '0';
		} else if(*pSrc >= 'A' && *pSrc <= 'F') {
			*pDst |= *pSrc - 'A' + 10;
		} else if(*pSrc >= 'a' && *pSrc <= 'f') {
			*pDst |= *pSrc - 'a' + 10;
		} else {
			*pDst |= 0;
		}
		pSrc++;
		pDst++;
	}

	return nSrcLength;
}

int
ucstr_strcasecmp(const char *s1, const char *s2)
{
	const UC_U8 *cm = ucstr_charmap;
	const UC_U8 *us1 = (const UC_U8 *)s1;
	const UC_U8 *us2 = (const UC_U8 *)s2;

	while (cm[*us1] == cm[*us2++])
		if (*us1++ == '\0')
			return (0);
	return (cm[*us1] - cm[*--us2]);
}

int
ucstr_strncasecmp(const char *s1, const char *s2, int n)
{
	if (n != 0) {
		const UC_U8 *cm = ucstr_charmap;
		const UC_U8 *us1 = (const UC_U8 *)s1;
		const UC_U8 *us2 = (const UC_U8 *)s2;

		do {
			if (cm[*us1] != cm[*us2++])
				return (cm[*us1] - cm[*--us2]);
			if (*us1++ == '\0')
				break;
		} while (--n != 0);
	}
	return (0);
}

char *
ucstr_strcasestr(const char *s, const char *find)
{
	char c, sc;
	size_t len;

	if ((c = *find++) != 0) {
		c = (char)tolower((unsigned char)c);
		len = strlen(find);
		do {
			do {
				if ((sc = *s++) == 0)
					return (NULL);
			} while ((char)tolower((unsigned char)sc) != c);
		} while (ucstr_strncasecmp(s, find, len) != 0);
		s--;
	}
	return ((char *)s);
}

char *
ucstr_strcasechr(const char* s1,const char c2)
{
	if(s1 == NULL) {
		return NULL;
	}

	while(*s1){
		if(*s1 == c2
			|| *s1 == ((c2 >= 'a' && c2 <= 'z') ? c2 - 32 : c2)
			|| *s1 == ((c2 >= 'A' && c2 <= 'Z') ? c2 + 32 : c2)) {
			return (char*)s1;
		}
		s1++;
	}
	return NULL;
}

/***************************************************************
 * Function: uc_str_match
 * Description - uc_str_match(ab?d*e, abcde) return OK
 */
int
ucstr_str_match(char *src_str, char *dst_str)
{
	while (*dst_str != '\0' && *src_str != '\0') {
		if (*src_str == '*' && *(src_str + 1) == '\0') {
			return OK;
		}
		if (*src_str == '*') {
			src_str++;
			while (*dst_str != '\0') {
				if (ucstr_str_match(src_str, dst_str) == OK) {
					return OK;
				}
				dst_str++;
			}
			return ERROR;
		} else {
			while (*src_str == '?') {
				src_str++;
				dst_str++;
			}
			if (*src_str == '*') {
				continue;
			}else if (*src_str != *dst_str) {
				return ERROR;
			}else if (*src_str != '\0') {
				src_str++;
				dst_str++;
			}
		}
	}
	if (*src_str == *dst_str || (*src_str == '*' && *dst_str == '\0')) {
		return OK;
	}
	return ERROR;
}

void
ucstr_set_flag(UC_U8 *src, int bit, int flag)
{
	if (flag == 0) {
		src[bit / 8] &= (~ucstr_flag_key[bit % 8]);
	} else {
		src[bit / 8] |= ucstr_flag_key[bit % 8];
	}
}

int
ucstr_get_flag(UC_U8 *src, int bit)
{
	return (src[bit / 8] & ucstr_flag_key[bit % 8]);
}

int
ucstr_divide_fun(char *pSrc, char *pKey, int(*pFun)(int str_index, char *pStr, void *p1, void *p2), void *p1, void *p2)
{
	int str_idx = 0;
	char tmp_buf[UC_BUF_LEN_2K];
	char *pStart = tmp_buf;
	char *p = NULL;

	if(pFun == NULL || pKey == NULL || pSrc == NULL || strlen(pSrc) <= 0) {
		return ERROR;
	}

	uc_strncpy(tmp_buf, pSrc, sizeof(tmp_buf));

	while((p = strsep(&pStart, pKey)) != NULL) {
		if(pFun(str_idx, p, p1, p2) == ERROR) {
			str_idx++;
			break;
		}
		str_idx++;
	}

	return str_idx;
}

UC_U8 *
ucstr_memmem(const UC_U8 *haystack, int haystack_len, const UC_U8 *needle, int needle_len)
{
	int i = 0;

	if(haystack_len < needle_len) {
		return NULL;
	}

	for(i = 0; i < haystack_len - needle_len + 1; i++) {
		if(memcmp((void *)(haystack + i), (void *)needle, needle_len) == 0) {
			return (UC_U8 *)(haystack + i);
		}
	}

	return NULL;
}

int
ucstr_trim_to(char *dst, char *src, int max_dst_len)
{
	int i = 0;
	int len = 0;
	int head = -1;
	int tail = -1;

	if(dst != NULL && dst != src) {
		*dst = 0;
	}

	if(dst == NULL || src == NULL) {
		return -1;
	}

	len = strlen(src);
	for(i = 0; i < len; i++) {
		if(src[i] != ' ' && src[i] != '\r' && src[i] != '\n' && src[i] != '\t') {
			head = i;
			break;
		}
	}

	if(head >= 0) {
		for(i = len - 1; i >= 0; i--) {
			if(src[i] != ' ' && src[i] != '\r' && src[i] != '\n' && src[i] != '\t') {
				tail = i;
				break;
			}
		}
		len = tail - head + 1;
		if(max_dst_len > 0) {
			len = uc_min(len, max_dst_len - 1);
		}
		if(len > 0) {
			memmove(dst, src + head, len);
			dst[len] = 0;
			return len;
		} else {
			return 0;
		}
	} else {
		return 0;
	}
}

UC_U32
ucstr_hash_key(char *str)
{
	UC_U32 hash = 5381;

	while (*str) {
		hash += (hash << 5) + (*str++);
	}

	return hash;
}

char *
ucstr_replace(char *src, char *key, char *replace_as)
{
	char *pTmp = src;
	char *pTmp1 = NULL;
	int key_len = strlen(key);
	int rpa_len = strlen(replace_as);

	while(*pTmp > 0) {
		pTmp1 = strstr(pTmp, key);
		if(pTmp1 == NULL) {
			break;
		}
		if(rpa_len != key_len) {
			memmove(pTmp1 + rpa_len, pTmp1 + key_len, strlen(pTmp1 + key_len) + 1);
		}
		memcpy(pTmp1, replace_as, rpa_len);
		pTmp += rpa_len;
	}

	return src;
}

char *
ucstr_get_line(char *p_start, char *p_end, char *line_buf, int buf_len)
{
	char *p = p_start;
	int buffer_offset = 0;
#define IS_LINE_END(c) ((c) == '\n' || (c) == '\r')

	line_buf[0] = '\0';
	while (p < p_end) {
		if (IS_LINE_END(*p)) {
			p++;
		} else {
			break;
		}
	}

	while (p < p_end) {
		if (!IS_LINE_END(*p)) {
			if (buffer_offset + 1 < buf_len) {
				line_buf[buffer_offset] = *p;
				buffer_offset++;
				p++;
			} else {
				uc_err("str get line error, line too long\n");
				return NULL;
			}
		} else {
			line_buf[buffer_offset] = '\0';
			break;
		}
	}

	return p;
}

int
ucstr_path_fmt(char *src, int head, int tail)
{
	char *pTmp = src;
	int if_last_key = 0;
	int src_len = strlen(src);

	while(*pTmp != 0) {
		if(*pTmp == '\\') {
			*src = '/';
		}

		if(*pTmp == '/') {
			if_last_key++;
			if(if_last_key >= 2) {
				memmove(pTmp, pTmp + 1, src_len - (pTmp - src) + 1);
				src_len--;
				continue;
			}
		} else {
			if_last_key = 0;
		}
		pTmp++;
	}

	if(src_len > 0) {
		if(src[0] == '/') {
			if(head <= 0) {
				memmove(src, src + 1, src_len);
				src_len--;
			}
		} else {
			if(head > 0) {
				src_len++;
				memmove(src + 1, src, src_len);
				src[0] = '/';
			}
		}

		if(src[src_len - 1] == '/') {
			if(tail <= 0) {
				src_len--;
				src[src_len] = 0;
			}
		} else {
			if(tail > 0) {
				src[src_len] = '/';
				src_len++;
				src[src_len] = 0;
			}
		}
	}

	return src_len;
}

#ifdef __cplusplus
}
#endif
